---
title: "Análisis Electoral Comparativo MAGDALENA"
subtitle: "Elecciones Presidenciales 2018-2022: Primera y Segunda Vuelta"
author: "Análisis Cuantitativo"
date: "`r Sys.Date()`"
format:
html:
self-contained: true
code-fold: false
code-tools: true
toc: true
toc-depth: 4
toc-location: left
theme: cosmo
page-layout: full
df-print: paged
execute:
echo: false
warning: false
message: false
---
```{r setup, include=FALSE}
knitr:: opts_chunk$ set (echo = FALSE , warning = FALSE , message = FALSE , fig.width = 10 , fig.height = 10 )
```
```{r librerias}
# Cargar librerías
library (tidyverse)
library (rio)
library (sf)
library (leaflet)
library (crosstalk)
library (DT)
library (scales)
library (htmltools)
library (plotly)
library (kableExtra)
library (patchwork)
library (ggrepel)
```
```{r cargar_datos, cache=T}
# Cargar bases de datos
# AJUSTA LA RUTA BASE según dónde esté guardado este .qmd
ruta_base <- "../../../data/electoral_data_all_XXXXX/04_add_id_puesto_geom/output/"
bd_2018 <- import (file.path (ruta_base, "bd_2018_electoral_geom.rds" )) %>% st_as_sf ()
bd_2022 <- import (file.path (ruta_base, "bd_2022_electoral_geom.rds" )) %>% st_as_sf ()
# Filtrar solo MAGDALENA
magdalena_2018 <- bd_2018 %>%
filter (dpto == "MAGDALENA" ) %>%
filter (! st_is_empty (geometry))
magdalena_2022 <- bd_2022 %>%
filter (dpto == "MAGDALENA" ) %>%
filter (! st_is_empty (geometry))
```
```{r preparar_datos_mejorado}
# ========================
# COMPARACIÓN 2018 vs 2022
# ========================
datos_comparacion <- magdalena_2018 %>%
st_drop_geometry () %>%
select (
id_puesto, puesto_nom, dpto, mpio, divipola,
Petro_v1_2018 = Petro_v1,
Petro_v2_2018 = Petro_v2,
Duque_v1_2018 = Duque_v1,
Duque_v2_2018 = Duque_v2,
t_votos_v1_2018 = t_votos_puesto_v1,
t_votos_v2_2018 = t_votos_puesto_v2
) %>%
full_join (
magdalena_2022 %>%
st_drop_geometry () %>%
select (
id_puesto,
puesto_nom_2022 = puesto_nom,
mpio_2022 = mpio,
Petro_v1_2022 = Petro_v1,
Petro_v2_2022 = Petro_v2,
Hernandez_v1_2022 = Hernandez_v1,
Hernandez_v2_2022 = Hernandez_v2,
t_votos_v1_2022 = t_votos_puesto_v1,
t_votos_v2_2022 = t_votos_puesto_v2
),
by = "id_puesto"
) %>%
mutate (
# Consolidar identificadores
puesto_nom = coalesce (puesto_nom, puesto_nom_2022),
mpio = coalesce (mpio, mpio_2022),
# VARIACIONES ABSOLUTAS Y RELATIVAS =====
# Petro
var_abs_Petro_v1 = Petro_v1_2022 - Petro_v1_2018,
var_abs_Petro_v2 = Petro_v2_2022 - Petro_v2_2018,
var_Petro_v1 = ((Petro_v1_2022 - Petro_v1_2018) / Petro_v1_2018) * 100 ,
var_Petro_v2 = ((Petro_v2_2022 - Petro_v2_2018) / Petro_v2_2018) * 100 ,
# Contrincantes
var_abs_Contrincante_v1 = Hernandez_v1_2022 - Duque_v1_2018,
var_abs_Contrincante_v2 = Hernandez_v2_2022 - Duque_v2_2018,
var_Contrincante_v1 = ((Hernandez_v1_2022 - Duque_v1_2018) / Duque_v1_2018) * 100 ,
var_Contrincante_v2 = ((Hernandez_v2_2022 - Duque_v2_2018) / Duque_v2_2018) * 100 ,
# PARTICIPACIÓN ELECTORAL =====
var_participacion_v1 = ((t_votos_v1_2022 - t_votos_v1_2018) / t_votos_v1_2018) * 100 ,
var_participacion_v2 = ((t_votos_v2_2022 - t_votos_v2_2018) / t_votos_v2_2018) * 100 ,
# SHARE DE VOTOS (%) =====
share_Petro_v1_2018 = (Petro_v1_2018 / t_votos_v1_2018) * 100 ,
share_Petro_v2_2018 = (Petro_v2_2018 / t_votos_v2_2018) * 100 ,
share_Petro_v1_2022 = (Petro_v1_2022 / t_votos_v1_2022) * 100 ,
share_Petro_v2_2022 = (Petro_v2_2022 / t_votos_v2_2022) * 100 ,
share_Duque_v1_2018 = (Duque_v1_2018 / t_votos_v1_2018) * 100 ,
share_Duque_v2_2018 = (Duque_v2_2018 / t_votos_v2_2018) * 100 ,
share_Hernandez_v1_2022 = (Hernandez_v1_2022 / t_votos_v1_2022) * 100 ,
share_Hernandez_v2_2022 = (Hernandez_v2_2022 / t_votos_v2_2022) * 100 ,
# MARGEN DE VICTORIA =====
margen_v1_2018 = abs (Petro_v1_2018 - Duque_v1_2018),
margen_v2_2018 = abs (Petro_v2_2018 - Duque_v2_2018),
margen_v1_2022 = abs (Petro_v1_2022 - Hernandez_v1_2022),
margen_v2_2022 = abs (Petro_v2_2022 - Hernandez_v2_2022),
# Ganador
ganador_v1_2018 = ifelse (Petro_v1_2018 > Duque_v1_2018, "Petro" , "Duque" ),
ganador_v2_2018 = ifelse (Petro_v2_2018 > Duque_v2_2018, "Petro" , "Duque" ),
ganador_v1_2022 = ifelse (Petro_v1_2022 > Hernandez_v1_2022, "Petro" , "Hernández" ),
ganador_v2_2022 = ifelse (Petro_v2_2022 > Hernandez_v2_2022, "Petro" , "Hernández" ),
# COMPETITIVIDAD =====
# Índice de competitividad (0-100, donde 0 = máxima competitividad)
competitividad_v1_2018 = abs (share_Petro_v1_2018 - share_Duque_v1_2018),
competitividad_v2_2018 = abs (share_Petro_v2_2018 - share_Duque_v2_2018),
competitividad_v1_2022 = abs (share_Petro_v1_2022 - share_Hernandez_v1_2022),
competitividad_v2_2022 = abs (share_Petro_v2_2022 - share_Hernandez_v2_2022),
# VOLATILIDAD ELECTORAL =====
# Cambio en el share de Petro entre elecciones
volatilidad_Petro_v1 = abs (share_Petro_v1_2022 - share_Petro_v1_2018),
volatilidad_Petro_v2 = abs (share_Petro_v2_2022 - share_Petro_v2_2018),
# FLIP DE PUESTOS =====
# Puestos que cambiaron de ganador
flip_v1 = ganador_v1_2018 != ganador_v1_2022,
flip_v2 = ganador_v2_2018 != ganador_v2_2022,
# Limpiar infinitos y NaN
across (where (is.numeric), ~ ifelse (is.infinite (.) | is.nan (.), NA , .)),
# Indicadores de presencia
solo_2018 = ! is.na (Petro_v1_2018) & is.na (Petro_v1_2022),
solo_2022 = is.na (Petro_v1_2018) & ! is.na (Petro_v1_2022),
ambos = ! is.na (Petro_v1_2018) & ! is.na (Petro_v1_2022)
)
# ======================
# REINCORPORAR GEOMETRÍA
# ======================
datos_mapa <- magdalena_2018 %>%
select (id_puesto, geometry) %>%
left_join (datos_comparacion, by = "id_puesto" ) %>%
st_as_sf () %>%
filter (! is.na (id_puesto), ! st_is_empty (geometry))
# Coordenadas para leaflet
datos_mapa <- datos_mapa %>%
mutate (
coords = st_coordinates (geometry),
lon = coords[, 1 ],
lat = coords[, 2 ]
) %>%
select (- coords)
```
::: {.callout-note icon=false}
## 📌 Resumen
Este análisis compara el comportamiento electoral en MAGDALENA entre las elecciones presidenciales de 2018 y 2022, enfocándose en:
- **Gustavo Petro**: Comparación consigo mismo (2018 vs 2022)
- **Contrincantes**: Iván Duque (2018) vs Rodolfo Hernández (2022)
- **Análisis por puesto de votación**
:::
---
# I. PANORAMA GENERAL
## Resumen Cuantitativo
```{r resumen_general}
# Calcular totales
resumen <- tibble (
Categoría = c ("Cobertura" , "" , "" , "" , "Participación" , "" , "" , "" ),
Indicador = c (
"Total Puestos Únicos" ,
"Puestos en Ambas Elecciones" ,
"Puestos Solo en 2018" ,
"Puestos Solo en 2022" ,
"Total Votos 2018 - Primera Vuelta" ,
"Total Votos 2018 - Segunda Vuelta" ,
"Total Votos 2022 - Primera Vuelta" ,
"Total Votos 2022 - Segunda Vuelta"
),
Valor = c (
nrow (datos_mapa),
sum (datos_comparacion$ ambos, na.rm = TRUE ),
sum (datos_comparacion$ solo_2018, na.rm = TRUE ),
sum (datos_comparacion$ solo_2022, na.rm = TRUE ),
sum (datos_comparacion$ t_votos_v1_2018, na.rm = TRUE ),
sum (datos_comparacion$ t_votos_v2_2018, na.rm = TRUE ),
sum (datos_comparacion$ t_votos_v1_2022, na.rm = TRUE ),
sum (datos_comparacion$ t_votos_v2_2022, na.rm = TRUE )
)
)
resumen %>%
mutate (Valor = comma (Valor)) %>%
knitr:: kable (align = c ("l" , "l" , "r" )) %>%
kable_styling (bootstrap_options = c ("striped" , "hover" , "condensed" ), full_width = FALSE ) %>%
pack_rows ("Cobertura Geográfica" , 1 , 4 ) %>%
pack_rows ("Participación Electoral" , 5 , 8 )
```
## Resultados MAGDALENA
```{r tabla_agregada_mejorada}
# Crear tabla resumen con métricas adicionales
tabla_magdalena <- tibble (
Puesto = "MAGDALENA (TOTAL)" ,
# Petro Primera Vuelta
Petro_2018_v1 = sum (datos_comparacion$ Petro_v1_2018, na.rm = TRUE ),
Petro_2022_v1 = sum (datos_comparacion$ Petro_v1_2022, na.rm = TRUE ),
Var_Abs_Petro_v1 = Petro_2022_v1 - Petro_2018_v1,
Var_Petro_v1 = ((Petro_2022_v1 - Petro_2018_v1) / Petro_2018_v1) * 100 ,
# Petro Segunda Vuelta
Petro_2018_v2 = sum (datos_comparacion$ Petro_v2_2018, na.rm = TRUE ),
Petro_2022_v2 = sum (datos_comparacion$ Petro_v2_2022, na.rm = TRUE ),
Var_Abs_Petro_v2 = Petro_2022_v2 - Petro_2018_v2,
Var_Petro_v2 = ((Petro_2022_v2 - Petro_2018_v2) / Petro_2018_v2) * 100 ,
# Contrincantes Primera Vuelta
Duque_2018_v1 = sum (datos_comparacion$ Duque_v1_2018, na.rm = TRUE ),
Hernandez_2022_v1 = sum (datos_comparacion$ Hernandez_v1_2022, na.rm = TRUE ),
Var_Abs_Contr_v1 = Hernandez_2022_v1 - Duque_2018_v1,
Var_Contrincante_v1 = ((Hernandez_2022_v1 - Duque_2018_v1) / Duque_2018_v1) * 100 ,
# Contrincantes Segunda Vuelta
Duque_2018_v2 = sum (datos_comparacion$ Duque_v2_2018, na.rm = TRUE ),
Hernandez_2022_v2 = sum (datos_comparacion$ Hernandez_v2_2022, na.rm = TRUE ),
Var_Abs_Contr_v2 = Hernandez_2022_v2 - Duque_2018_v2,
Var_Contrincante_v2 = ((Hernandez_2022_v2 - Duque_2018_v2) / Duque_2018_v2) * 100
)
# Mostrar tabla formateada
tabla_magdalena %>%
mutate (
across (c (Petro_2018_v1, Petro_2022_v1, Petro_2018_v2, Petro_2022_v2,
Duque_2018_v1, Hernandez_2022_v1, Duque_2018_v2, Hernandez_2022_v2), ~ comma (.x)),
across (starts_with ("Var_Abs" ), ~ paste0 (ifelse (.x > 0 , "+" , "" ), comma (.x))),
across (c (Var_Petro_v1, Var_Petro_v2, Var_Contrincante_v1, Var_Contrincante_v2),
~ paste0 (ifelse (.x > 0 , "+" , "" ), round (.x, 2 ), "%" ))
) %>%
knitr:: kable (
col.names = c (
"Región" ,
"2018" , "2022" , "Δ Abs" , "Δ%" ,
"2018" , "2022" , "Δ Abs" , "Δ%" ,
"2018 (Duque)" , "2022 (Hernández)" , "Δ Abs" , "Δ%" ,
"2018 (Duque)" , "2022 (Hernández)" , "Δ Abs" , "Δ%"
),
align = c ("l" , rep ("r" , 16 ))
) %>%
kable_styling (bootstrap_options = c ("striped" , "hover" , "condensed" )) %>%
add_header_above (c (" " = 1 , "Primera Vuelta" = 4 , "Segunda Vuelta" = 4 ,
"Primera Vuelta" = 4 , "Segunda Vuelta" = 4 )) %>%
add_header_above (c (" " = 1 , "GUSTAVO PETRO" = 8 , "CONTRINCANTES" = 8 ))
```
---
# II. ANÁLISIS DE VARIACIONES
## Distribución de Variaciones - Gustavo Petro
```{r distribucion_petro_mejorada, fig.height=8}
p1 <- datos_comparacion %>%
filter (! is.na (var_Petro_v1), ambos) %>%
ggplot (aes (x = var_Petro_v1)) +
geom_histogram (aes (y = after_stat (density)), bins = 40 , fill = "#e74c3c" , alpha = 0.6 ) +
geom_density (color = "#c0392b" , linewidth = 1.2 ) +
geom_vline (xintercept = 0 , linetype = "dashed" , color = "black" , linewidth = 1 ) +
geom_vline (xintercept = median (datos_comparacion$ var_Petro_v1, na.rm = TRUE ),
linetype = "dotted" , color = "#2c3e50" , linewidth = 1 ) +
labs (
title = "Variación Petro - Primera Vuelta" ,
subtitle = paste0 ("Mediana: " , round (median (datos_comparacion$ var_Petro_v1, na.rm = TRUE ), 1 ), "%" ),
x = "Variación (%)" ,
y = "Densidad"
) +
theme_minimal (base_size = 12 )
p2 <- datos_comparacion %>%
filter (! is.na (var_Petro_v2), ambos) %>%
ggplot (aes (x = var_Petro_v2)) +
geom_histogram (aes (y = after_stat (density)), bins = 40 , fill = "#3498db" , alpha = 0.6 ) +
geom_density (color = "#2980b9" , linewidth = 1.2 ) +
geom_vline (xintercept = 0 , linetype = "dashed" , color = "black" , linewidth = 1 ) +
geom_vline (xintercept = median (datos_comparacion$ var_Petro_v2, na.rm = TRUE ),
linetype = "dotted" , color = "#2c3e50" , linewidth = 1 ) +
labs (
title = "Variación Petro - Segunda Vuelta" ,
subtitle = paste0 ("Mediana: " , round (median (datos_comparacion$ var_Petro_v2, na.rm = TRUE ), 1 ), "%" ),
x = "Variación (%)" ,
y = "Densidad"
) +
theme_minimal (base_size = 12 )
p1 / p2
```
## Distribución de Variaciones - Contrincantes
```{r distribucion_contrincantes_mejorada, fig.height=8}
p3 <- datos_comparacion %>%
filter (! is.na (var_Contrincante_v1), ambos) %>%
ggplot (aes (x = var_Contrincante_v1)) +
geom_histogram (aes (y = after_stat (density)), bins = 40 , fill = "#2ecc71" , alpha = 0.6 ) +
geom_density (color = "#27ae60" , linewidth = 1.2 ) +
geom_vline (xintercept = 0 , linetype = "dashed" , color = "black" , linewidth = 1 ) +
geom_vline (xintercept = median (datos_comparacion$ var_Contrincante_v1, na.rm = TRUE ),
linetype = "dotted" , color = "#2c3e50" , linewidth = 1 ) +
labs (
title = "Variación Contrincantes - Primera Vuelta" ,
subtitle = paste0 ("Duque (2018) vs Hernández (2022) | Mediana: " ,
round (median (datos_comparacion$ var_Contrincante_v1, na.rm = TRUE ), 1 ), "%" ),
x = "Variación (%)" ,
y = "Densidad"
) +
theme_minimal (base_size = 12 )
p4 <- datos_comparacion %>%
filter (! is.na (var_Contrincante_v2), ambos) %>%
ggplot (aes (x = var_Contrincante_v2)) +
geom_histogram (aes (y = after_stat (density)), bins = 40 , fill = "#f39c12" , alpha = 0.6 ) +
geom_density (color = "#e67e22" , linewidth = 1.2 ) +
geom_vline (xintercept = 0 , linetype = "dashed" , color = "black" , linewidth = 1 ) +
geom_vline (xintercept = median (datos_comparacion$ var_Contrincante_v2, na.rm = TRUE ),
linetype = "dotted" , color = "#2c3e50" , linewidth = 1 ) +
labs (
title = "Variación Contrincantes - Segunda Vuelta" ,
subtitle = paste0 ("Duque (2018) vs Hernández (2022) | Mediana: " ,
round (median (datos_comparacion$ var_Contrincante_v2, na.rm = TRUE ), 1 ), "%" ),
x = "Variación (%)" ,
y = "Densidad"
) +
theme_minimal (base_size = 12 )
p3 / p4
```
## Correlación: Votos 2018 vs 2022
```{r correlacion_petro_interactivo, echo=FALSE}
library (plotly)
p <- datos_comparacion %>%
filter (ambos) %>%
ggplot (
aes (
x = Petro_v2_2018,
y = Petro_v2_2022,
text = paste0 (
"<b>Puesto:</b> " , puesto_nom, "<br>" ,
"<b>Municipio:</b> " , mpio, "<br>" ,
"<b>Votos 2018:</b> " , comma (Petro_v2_2018), "<br>" ,
"<b>Votos 2022:</b> " , comma (Petro_v2_2022), "<br>" ,
"<b>Variación (%):</b> " , round (var_Petro_v2, 1 )
)
)
) +
geom_point (
aes (color = var_Petro_v2, size = t_votos_v2_2022),
alpha = 0.6
) +
geom_abline (intercept = 0 , slope = 1 , linetype = "dashed" ) +
scale_color_gradient2 (
low = "#d73027" ,
mid = "#f7f7f7" ,
high = "#1a9850" ,
midpoint = 0
) +
scale_size_continuous (range = c (2 , 7 )) +
theme_minimal () +
theme (legend.position = "none" )
ggplotly (p, tooltip = "text" )
```
---
# III. KEY INSIGHTS (Petro - Segunda Vuelta)
## Mayores Ganancias de Petro
```{r top_ganancias}
datos_comparacion %>%
filter (ambos, ! is.na (var_abs_Petro_v2)) %>%
arrange (desc (var_abs_Petro_v2)) %>%
head (10 ) %>%
select (
Municipio = mpio,
Puesto = puesto_nom,
` 2018 ` = Petro_v2_2018,
` 2022 ` = Petro_v2_2022,
` Ganancia ` = var_abs_Petro_v2,
` Var % ` = var_Petro_v2
) %>%
mutate (
across (c (` 2018 ` , ` 2022 ` , Ganancia), ~ comma (.x)),
` Var % ` = paste0 ("+" , round (` Var % ` , 1 ), "%" )
) %>%
knitr:: kable (align = c ("l" , "l" , rep ("r" , 4 ))) %>%
kable_styling (bootstrap_options = c ("striped" , "hover" , "condensed" ))
```
## Mayores Pérdidas de Petro
```{r top_perdidas}
datos_comparacion %>%
filter (ambos, ! is.na (var_abs_Petro_v2)) %>%
arrange (var_abs_Petro_v2) %>%
head (10 ) %>%
select (
Municipio = mpio,
Puesto = puesto_nom,
` 2018 ` = Petro_v2_2018,
` 2022 ` = Petro_v2_2022,
` Pérdida ` = var_abs_Petro_v2,
` Var % ` = var_Petro_v2
) %>%
mutate (
across (c (` 2018 ` , ` 2022 ` , Pérdida), ~ comma (.x)),
` Var % ` = paste0 (round (` Var % ` , 1 ), "%" )
) %>%
knitr:: kable (align = c ("l" , "l" , rep ("r" , 4 ))) %>%
kable_styling (bootstrap_options = c ("striped" , "hover" , "condensed" ))
```
## Puestos que Cambiaron de Ganador entre elecciones (Flips)
```{r analisis_flips}
flips_v2 <- datos_comparacion %>%
filter (ambos, flip_v2) %>%
select (
Municipio = mpio,
Puesto = puesto_nom,
` Ganador 2018 ` = ganador_v2_2018,
` Ganador 2022 ` = ganador_v2_2022,
` Margen 2018 ` = margen_v2_2018,
` Margen 2022 ` = margen_v2_2022
) %>%
mutate (
across (c (` Margen 2018 ` , ` Margen 2022 ` ), ~ comma (.x))
)
cat (paste0 ("**Total de puestos que cambiaron de ganador (Segunda Vuelta): " ,
nrow (flips_v2), "** \n\n " ))
if (nrow (flips_v2) > 0 ) {
flips_v2 %>%
head (15 ) %>%
knitr:: kable (align = c ("l" , "l" , "c" , "c" , "r" , "r" )) %>%
kable_styling (bootstrap_options = c ("striped" , "hover" , "condensed" ))
}
```
---
# IV. ANÁLISIS ESPACIAL
## Mapa Interactivo de Puestos
**Instrucciones:**
- Haz clic en cualquier punto para ver análisis detallado
- Filtra por municipio usando el selector
- **Tamaño de puntos:** Proporcional a la participación electoral en 2ª vuelta (más votos = punto más grande)
- **Colores - Variación Petro Segunda Vuelta:**
- 🔴 Rojo oscuro: -50% o más
- 🟠 Naranja: -50% a -25%
- 🟡 Amarillo: -25% a 25%
- 🟢 Verde claro: 25% a 50%
- 🟢 Verde oscuro: 50% o más
- ⚫ Gris: Sin datos
::: {.panel-tabset}
### Mapa con Filtros
```{r mapa_interactivo, fig.height=10}
# Calcular tamaños de radio proporcionales a participación
datos_mapa <- datos_mapa %>%
mutate (
# Usar votos de segunda vuelta 2022 (o 2018 si no hay 2022)
votos_referencia = coalesce (t_votos_v2_2022, t_votos_v2_2018, 0 ),
# Escalar radius entre 4 y 18 basado en participación (raíz cuadrada para mejor visualización)
radius_scaled = scales:: rescale (sqrt (votos_referencia), to = c (4 , 18 ))
)
# Preparar datos para crosstalk
datos_compartidos <- SharedData$ new (
datos_mapa %>%
mutate (
mpio = ifelse (is.na (mpio), "Sin municipio" , mpio),
puesto_nom = ifelse (is.na (puesto_nom), "Sin nombre" , puesto_nom)
),
key = ~ id_puesto
)
# Paleta de colores con rangos
pal <- colorBin (
palette = c ("#d73027" , "#fc8d59" , "#fee08b" , "#d9ef8b" , "#91cf60" , "#1a9850" ),
domain = datos_mapa$ var_Petro_v2,
bins = c (- Inf ,- 50 , - 25 , 25 , 50 , 100 , Inf ),
na.color = "#808080"
)
# Filtro por municipio
filter_select (
id = "municipio" ,
label = "Selecciona municipio:" ,
sharedData = datos_compartidos,
group = ~ mpio,
multiple = TRUE
)
# Crear el mapa con fondo claro, más grande y puntos proporcionales
leaflet (datos_compartidos, height = 750 , width = "100%" ) %>%
# Usar CartoDB Positron para fondo minimalista y claro
addProviderTiles (providers$ CartoDB.Positron) %>%
addCircleMarkers (
lng = ~ lon,
lat = ~ lat,
radius = ~ radius_scaled, # Radio variable según participación
color = "#2c3e50" , # Borde oscuro para mejor contraste
fillColor = ~ pal (var_Petro_v2),
fillOpacity = 0.7 ,
stroke = TRUE ,
weight = 1.5 ,
opacity = 0.9 ,
popup = ~ paste0 (
"<div style='width:520px; background-color:#ffffff; padding:15px; border-radius:8px; box-shadow:0 2px 8px rgba(0,0,0,0.15);'>" ,
"<h4 style='margin:0 0 10px 0; color:#2c3e50; border-bottom:2px solid #3498db; padding-bottom:8px;'><strong>" , puesto_nom, "</strong></h4>" ,
"<p style='margin:5px 0; font-size:13px;'><strong>Municipio:</strong> " , mpio, "</p>" ,
"<p style='margin:5px 0; font-size:13px;'><strong>ID:</strong> " , id_puesto, "</p>" ,
ifelse (solo_2018,
"<div style='margin:10px 0; padding:10px; background-color:#fff3cd; border-left:4px solid #ffc107; border-radius:4px;'><strong>⚠️ Solo datos 2018</strong></div>" ,
ifelse (solo_2022,
"<div style='margin:10px 0; padding:10px; background-color:#d1ecf1; border-left:4px solid #17a2b8; border-radius:4px;'><strong>ℹ️ Solo datos 2022</strong></div>" ,
"" )),
"<hr style='margin:15px 0; border:none; border-top:1px solid #ddd;'>" ,
"<table style='width:100%; border-collapse: collapse; font-size:12px; background-color:#ffffff;'>" ,
"<thead>" ,
"<tr style='background-color:#34495e; color:white;'>" ,
"<th colspan='4' style='padding:10px; text-align:center; border:1px solid #bdc3c7; font-size:13px;'>GUSTAVO PETRO</th>" ,
"</tr>" ,
"<tr style='background-color:#ecf0f1;'>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; font-weight:bold;'></th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>2018</th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>2022</th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>Δ</th>" ,
"</tr>" ,
"</thead>" ,
"<tbody style='background-color:#ffffff;'>" ,
"<tr style='background-color:#ffffff;'>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; background-color:#f8f9fa;'><strong>1ª Vuelta</strong></td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Petro_v1_2018), comma (Petro_v1_2018), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Petro_v1_2022), comma (Petro_v1_2022), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; font-weight:bold; background-color:#ffffff; color:" ,
ifelse (! is.na (var_Petro_v1) & var_Petro_v1 > 0 , "#27ae60" ,
ifelse (! is.na (var_Petro_v1) & var_Petro_v1 < 0 , "#c0392b" , "black" )), ";'>" ,
ifelse (! is.na (var_Petro_v1), paste0 (ifelse (var_Petro_v1 > 0 , "+" , "" ), round (var_Petro_v1, 1 ), "%" ), "N/A" ), "</td>" ,
"</tr>" ,
"<tr style='background-color:#ffffff;'>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; background-color:#f8f9fa;'><strong>2ª Vuelta</strong></td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Petro_v2_2018), comma (Petro_v2_2018), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Petro_v2_2022), comma (Petro_v2_2022), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; font-weight:bold; background-color:#ffffff; color:" ,
ifelse (! is.na (var_Petro_v2) & var_Petro_v2 > 0 , "#27ae60" ,
ifelse (! is.na (var_Petro_v2) & var_Petro_v2 < 0 , "#c0392b" , "black" )), ";'>" ,
ifelse (! is.na (var_Petro_v2), paste0 (ifelse (var_Petro_v2 > 0 , "+" , "" ), round (var_Petro_v2, 1 ), "%" ), "N/A" ), "</td>" ,
"</tr>" ,
"</tbody>" ,
"</table>" ,
"<div style='height:12px;'></div>" ,
"<table style='width:100%; border-collapse: collapse; font-size:12px; background-color:#ffffff;'>" ,
"<thead>" ,
"<tr style='background-color:#c0392b; color:white;'>" ,
"<th colspan='4' style='padding:10px; text-align:center; border:1px solid #bdc3c7; font-size:13px;'>CONTRINCANTES</th>" ,
"</tr>" ,
"<tr style='background-color:#ecf0f1;'>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; font-weight:bold;'></th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>Duque 2018</th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>Hernández 2022</th>" ,
"<th style='padding:6px; border:1px solid #bdc3c7; text-align:center; font-weight:bold;'>Δ</th>" ,
"</tr>" ,
"</thead>" ,
"<tbody style='background-color:#ffffff;'>" ,
"<tr style='background-color:#ffffff;'>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; background-color:#f8f9fa;'><strong>1ª Vuelta</strong></td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Duque_v1_2018), comma (Duque_v1_2018), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Hernandez_v1_2022), comma (Hernandez_v1_2022), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; font-weight:bold; background-color:#ffffff; color:" ,
ifelse (! is.na (var_Contrincante_v1) & var_Contrincante_v1 > 0 , "#27ae60" ,
ifelse (! is.na (var_Contrincante_v1) & var_Contrincante_v1 < 0 , "#c0392b" , "black" )), ";'>" ,
ifelse (! is.na (var_Contrincante_v1), paste0 (ifelse (var_Contrincante_v1 > 0 , "+" , "" ), round (var_Contrincante_v1, 1 ), "%" ), "N/A" ), "</td>" ,
"</tr>" ,
"<tr style='background-color:#ffffff;'>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; background-color:#f8f9fa;'><strong>2ª Vuelta</strong></td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Duque_v2_2018), comma (Duque_v2_2018), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; background-color:#ffffff;'>" ,
ifelse (! is.na (Hernandez_v2_2022), comma (Hernandez_v2_2022), "N/A" ), "</td>" ,
"<td style='padding:6px; border:1px solid #bdc3c7; text-align:right; font-weight:bold; background-color:#ffffff; color:" ,
ifelse (! is.na (var_Contrincante_v2) & var_Contrincante_v2 > 0 , "#27ae60" ,
ifelse (! is.na (var_Contrincante_v2) & var_Contrincante_v2 < 0 , "#c0392b" , "black" )), ";'>" ,
ifelse (! is.na (var_Contrincante_v2), paste0 (ifelse (var_Contrincante_v2 > 0 , "+" , "" ), round (var_Contrincante_v2, 1 ), "%" ), "N/A" ), "</td>" ,
"</tr>" ,
"</tbody>" ,
"</table>" ,
"<hr style='margin:15px 0; border:none; border-top:1px solid #ddd;'>" ,
"<p style='font-size:11px; color:#7f8c8d; margin:0; padding:8px; background-color:#f8f9fa; border-radius:4px;'><strong>Participación Δ:</strong> " ,
ifelse (! is.na (var_participacion_v2),
paste0 (ifelse (var_participacion_v2 > 0 , "+" , "" ), round (var_participacion_v2, 1 ), "% (2ª vuelta)" ),
"N/A" ),
"</p>" ,
"</div>"
),
label = ~ puesto_nom
) %>%
addLegend (
position = "bottomright" ,
pal = pal,
values = ~ var_Petro_v2,
title = "Variación Petro<br>2ª Vuelta (%)" ,
opacity = 0.8 ,
labFormat = function (type, cuts, p) {
cuts <- as.numeric (cuts)
paste0 (
ifelse (is.infinite (cuts[- length (cuts)]),
ifelse (cuts[- length (cuts)] < 0 , "< " , "" ),
cuts[- length (cuts)]),
" – " ,
ifelse (is.infinite (cuts[- 1 ]),
ifelse (cuts[- 1 ] > 0 , "> " , "" ),
cuts[- 1 ]),
"%"
)
},
na.label = "Sin datos"
)
```
### Tabla de Datos
```{r tabla_datos_completa}
datos_mapa %>%
st_drop_geometry () %>%
filter (ambos) %>%
select (
Municipio = mpio,
Puesto = puesto_nom,
` Petro 2018 V1 ` = Petro_v1_2018,
` Petro 2022 V1 ` = Petro_v1_2022,
` Δ Petro V1 (%) ` = var_Petro_v1,
` Petro 2018 V2 ` = Petro_v2_2018,
` Petro 2022 V2 ` = Petro_v2_2022,
` Δ Petro V2 (%) ` = var_Petro_v2,
` Participación Δ (%) ` = var_participacion_v2
) %>%
mutate (
across (contains ("2018" ) | contains ("2022" ), ~ comma (.x)),
across (contains ("Δ" ), ~ ifelse (! is.na (.x), paste0 (ifelse (.x > 0 , "+" , "" ), round (.x, 1 ), "%" ), "N/A" ))
) %>%
datatable (
filter = 'top' ,
options = list (
pageLength = 25 ,
scrollX = TRUE ,
dom = 'Bfrtip' ,
buttons = c ('copy' , 'csv' , 'excel' )
),
rownames = FALSE ,
extensions = 'Buttons'
)
```
:::
# V. ESTADÍSTICAS DETALLADAS POR MUNICIPIO
```{r tabla_municipios_detallada}
resumen_municipios <- datos_comparacion %>%
filter (ambos) %>%
group_by (mpio) %>%
summarise (
` N° Puestos ` = n (),
# Petro Primera Vuelta
` Petro 2018 V1 ` = sum (Petro_v1_2018, na.rm = TRUE ),
` Petro 2022 V1 ` = sum (Petro_v1_2022, na.rm = TRUE ),
` Δ Abs V1 ` = ` Petro 2022 V1 ` - ` Petro 2018 V1 ` ,
` Δ % V1 ` = ((` Petro 2022 V1 ` - ` Petro 2018 V1 ` ) / ` Petro 2018 V1 ` ) * 100 ,
# Petro Segunda Vuelta
` Petro 2018 V2 ` = sum (Petro_v2_2018, na.rm = TRUE ),
` Petro 2022 V2 ` = sum (Petro_v2_2022, na.rm = TRUE ),
` Δ Abs V2 ` = ` Petro 2022 V2 ` - ` Petro 2018 V2 ` ,
` Δ % V2 ` = ((` Petro 2022 V2 ` - ` Petro 2018 V2 ` ) / ` Petro 2018 V2 ` ) * 100 ,
# Participación
` Part. Δ % ` = mean (var_participacion_v2, na.rm = TRUE )
) %>%
arrange (desc (` Δ Abs V2 ` ))
resumen_municipios %>%
mutate (
across (c (` Petro 2018 V1 ` , ` Petro 2022 V1 ` , ` Δ Abs V1 ` ,
` Petro 2018 V2 ` , ` Petro 2022 V2 ` , ` Δ Abs V2 ` ), ~ comma (.x)),
across (c (` Δ % V1 ` , ` Δ % V2 ` , ` Part. Δ % ` ),
~ paste0 (ifelse (.x > 0 , "+" , "" ), round (.x, 1 ), "%" ))
) %>%
datatable (
filter = 'top' ,
options = list (
pageLength = 20 ,
scrollX = TRUE ,
dom = 'Bfrtip' ,
buttons = c ('copy' , 'csv' , 'excel' )
),
rownames = FALSE ,
extensions = 'Buttons'
) %>%
formatStyle (
'Δ % V2' ,
backgroundColor = styleInterval (0 , c ('#ffebee' , '#e8f5e9' ))
)
```
---
```{r footer, results='asis', echo=FALSE}
cat ('
<div style="text-align: center; margin-top: 40px; padding: 20px; background-color: #ecf0f1; border-radius: 8px;">
<strong style="font-size: 16px;">Análisis Electoral MAGDALENA</strong><br>
<span style="font-size: 14px;">Presidenciales 2018-2022</span><br>
<em style="font-size: 12px; color: #7f8c8d;">Comparación: Petro vs Petro | Duque (2018) vs Hernández (2022)</em>
</div>
' )
```